package tuding.android.bigplanettracks.tudingConnection;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import tuding.android.bigplanettracks.BigPlanet;
import tuding.android.bigplanettracks.maps.Logex;
import tuding.android.bigplanettracks.util.Preferences;
import android.os.Handler;
import android.os.Message;
//import android.util.Log;

/**
 * I prefer classes in this package to handle all tuding connection stuffs.
 * */
public class BaseConnection {

	/** Tuding username. */
	private String Username = "";
	/** Tuding password. */
	private String Password = "";	

	private Handler viewHandler = null;
	private myThread exportThread = null;

	public static final int UNKNOWN_ERROR = 2;
	public static final int LOGIN_FAILED = 1;
	public static final int LOGIN_SUCCESS = 0; 

	private static final String UN_PW_ERROR_TEXT = "PasswordInvalidconnect";
	private static final String NO_UN_TEXT = "NoUserNameProvidedconnect";
	private static final String LOGIN_SUCCESS_TEXT = "LoginSucceededconnect";

	public void setUsername(String username) {
		Username = username;
	}

	public void setPassword(String password) {
		Password = password;
	}
	
	public void setHandler(Handler handler) {
		this.viewHandler = handler;
	}

	class myThread extends Thread {
		
		public boolean stopped = true;

		public void run() {
			
			stopped = false;

			Message m = null;
			Logex.message("Message", "Connect tuding with username: " + Username);
			Logex.message("Message", "Connect tuding with password: " + Password);

			try{
				Logex.message("Message", "Connecting ...");

				Map<String, String> params = new HashMap<String, String>();
				params.put("do", "connect"); // Connecting test only
				params.put("username", Username);
				params.put("password", Password);

				String postUrl = BigPlanet.SERVER_ADDRESS+"android_upload.php";

				// Post to tuding.
				// Only handle the connecting process.
				String rc = postToTuding(postUrl, params, null);

				Logex.message("UPLOAD", "rc is "+rc);
				if (stopped) {
					Logex.message("Message", "Thread stopped.");
				} else if (rc.contains(UN_PW_ERROR_TEXT) || 
						rc.contains(NO_UN_TEXT)) {
					Logex.message("Message", "Failed to connect tuding due to invalid username/password.");

					//sent message back to TrackListViewAvtivity handler
					String obj = "Fail!";
					m = viewHandler.obtainMessage(LOGIN_FAILED, 0, 1, obj.toString());
					if(viewHandler != null)
						viewHandler.sendMessage(m);
					else
						throw new Error("viewHandler is Null");	

				} else if (!rc.contains(LOGIN_SUCCESS_TEXT)) {
					Logex.message("Message", "Failed to connect tuding due to unknown error.");

					//sent message back to TrackListViewAvtivity handler
					String obj = "Fail!";
					m = viewHandler.obtainMessage(UNKNOWN_ERROR, 0, 1, obj.toString());
					if(viewHandler != null)
						viewHandler.sendMessage(m);
					else
						throw new Error("viewHandler is Null");

				} else {
					//sent message back to TrackListViewAvtivity handler
					String obj = "Success!";
					m = viewHandler.obtainMessage(LOGIN_SUCCESS, 1, 1, obj);

					//Log.i("Message", "Login success with username: " + Username);
					//Log.i("Message", "Login success with password: " + Password);

					Preferences.putUsername(Username);
					Preferences.putPassword(Password);

					if (viewHandler != null)
						viewHandler.sendMessage(m);
					else
						throw new Error("viewHandler is Null");
				}

			} catch(Exception e) {
				
				if (!stopped) {
					//sent message back to TrackListViewAvtivity handler
					Logex.message("Message", "Failed to connect tuding due to unknown error.");
					String obj = "Fail!";
					m = viewHandler.obtainMessage(UNKNOWN_ERROR, 0, 1, obj.toString());
					if(viewHandler != null)
						viewHandler.sendMessage(m);
					else
						throw new Error("viewHandler is Null");
					e.printStackTrace();
				} else {
					Logex.message("Message", "Thread stopped.");
				}

			} finally {
				Logex.message("Message", "Dismiss login dialog.");
				if (BigPlanet.loginDialog != null) {
					BigPlanet.loginDialog.dismiss();
				}
			}
		}// end of run

		
	}
	
	/**
	 * Copyed from internet by pengfei
	 * @param actionUrl
	 * @param params
	 * @param files
	 * @return
	 * @throws IOException
	 */
	public static String postToTuding(String actionUrl, Map<String, String> params, 
			Map<String, File> files) throws IOException { 
		
		Logex.message("UPLOAD", "url is "+actionUrl);

		String BOUNDARY = java.util.UUID.randomUUID().toString();
		String PREFIX = "--" , LINEND = "\r\n";
		String MULTIPART_FROM_DATA = "multipart/form-data"; 
		String CHARSET = "UTF-8";

		URL uri = new URL(actionUrl); 
		HttpURLConnection conn = (HttpURLConnection) uri.openConnection(); 
		int timeoutval = (files!=null)?files.size():0;
		int finaltimeoutval = (timeoutval < 3) ? 60000 : ((1+timeoutval) * 15000);
		conn.setReadTimeout(finaltimeoutval); //TODO: need payattention, as Mobile internet is not as good as lan,
		conn.setConnectTimeout(30000);
		conn.setDoInput(true);
		conn.setDoOutput(true); 
		conn.setUseCaches(false); 
		conn.setRequestMethod("POST"); 
		conn.setRequestProperty("connection", "keep-alive"); 
		conn.setRequestProperty("Charsert", "UTF-8"); 
		conn.setRequestProperty("Content-Type", MULTIPART_FROM_DATA + ";boundary=" + BOUNDARY); 

		// Params
		StringBuilder sb = new StringBuilder(); 
		for (Map.Entry<String, String> entry : params.entrySet()) { 
			sb.append(PREFIX); 
			sb.append(BOUNDARY); 
			sb.append(LINEND); 
			sb.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + LINEND);
			sb.append("Content-Type: text/plain; charset=" + CHARSET+LINEND);
			sb.append("Content-Transfer-Encoding: 8bit" + LINEND);
			sb.append(LINEND);
			sb.append(entry.getValue()); 
			sb.append(LINEND); 
		} 

		DataOutputStream outStream = new DataOutputStream(conn.getOutputStream()); 
		outStream.write(sb.toString().getBytes()); 

		// Files
		if(files!=null){
			int piccnt = 0;
			for (Map.Entry<String, File> file: files.entrySet()) { 
				StringBuilder sb1 = new StringBuilder(); 
				sb1.append(PREFIX); 
				sb1.append(BOUNDARY); 
				sb1.append(LINEND); 
				
				//sb1.append("Content-Disposition: form-data; name=\"gpxfile"+(i++)+"\"; filename=\""+file.getKey()+"\""+LINEND);
				if(file.getKey() != "gpxfile") {
					sb1.append("Content-Disposition: form-data; name=\"pics"+piccnt+"\"; filename=\""+file.getKey()+"\""+LINEND);
					piccnt++;
				} else {
					sb1.append("Content-Disposition: form-data; name=\"gpxfile\"; filename=\""+file.getKey()+"\""+LINEND);
				}
				sb1.append("Content-Type: application/octet-stream; charset="+CHARSET+LINEND);
				sb1.append(LINEND);
				outStream.write(sb1.toString().getBytes()); 
				
				Logex.message("UPLOAD", sb1.toString());

				InputStream is = new FileInputStream(file.getValue());
				byte[] buffer = new byte[1024]; 
				int len = 0; 
				while ((len = is.read(buffer)) != -1) { 
					outStream.write(buffer, 0, len); 
				}

				is.close(); 
				outStream.write(LINEND.getBytes()); 
			} 
		}

		// End of request
		byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes(); 
		outStream.write(end_data); 
		outStream.flush(); 

		// get response code
		int res = conn.getResponseCode(); 
		InputStream in = null;
		StringBuilder sb2 = new StringBuilder(); 
		Logex.message("UPLOAD", ""+res);
		Logex.message("UPLOAD", ""+conn.getResponseMessage());
		if (res == 200) {
			in = conn.getInputStream(); 
			int ch; 

			while ((ch = in.read()) != -1) { 
				sb2.append((char) ch); 
			} 
		} else {
			return ""+res;
		}

		// Return input stream
		return sb2 == null ? null : sb2.toString(); 
	}

	
	public void connect() {
		Logex.message("Message", "Start connecting Tuding");
		exportThread = new myThread();
		exportThread.setName("Connect Thread");
		exportThread.start();
	}
	
	public void stopConnection() {
		Logex.message("Message", "Stop connecting Tuding");
		if (exportThread != null) {
			exportThread.stopped = true;
		}
	}
}
